﻿using ezCloud.Api.Common;
using ezCloud.Data;
using Microsoft.AspNet.Identity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Linq.SqlClient;
using System.Data.SqlTypes;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web.Http;

namespace ezCloud.Api.Controllers
{
    [ApiAuthorize]
    [RoutePrefix("api/POS")]
    public class POSController : ezController
    {
        public bool CheckIfPOSModuleUsed(Hotels currentHotel)
        {
            var result = currentHotel.EzHotelModulesList.Where(module => module.EzModules.ModuleCode == "POS" && module.EzModules.Status == true && module.Status == true).ToList().Count > 0;
            return result;
        }


        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetAllPOSData")]
        public async Task<IHttpActionResult> GetAllPOSData(int? draftId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                var posConfig = currentHotel.POSConfigsList.FirstOrDefault();
                var currencies = currentHotel.MoneyList;
                var currenciesISO = new List<Currencies>();
                foreach (var currency in currencies)
                {
                    var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                    if (iso != null)
                    {
                        currenciesISO.Add(iso);
                    }
                }
                var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
                if (defaultCurrency == null)
                {
                    defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
                }
                var extraServices = new
                {
                    ExtraServiceTypes = currentHotel.ExtraServiceTypesList.Where(type => type.ExtraServiceTypeName != "COMPENSATION"),
                    ExtraServiceCategories = currentHotel.ExtraServiceCategoriesList.Where(cat => cat.IsHidden == false),
                    ExtraServiceItems = currentHotel.ExtraServiceItemsList.Where(item => item.ExtraServiceCategories.IsHidden == false && item.IsHidden == false )
                };
                var paymentMethods = context.PaymentMethods;
                var countries = context.Countries;
                var companyList = currentHotel.CompanyList.Where(comp => comp.IsAvailable == true).Select(s => new {
                    s.CompanyName,
                    s.CompanyCode,
                    s.CompanyId
                });
                object draftData = null;
                if (draftId != null)
                {
                    draftData = currentHotel.DrafPOSPaymentTravellerList.Single(draft => draft.DrafPOSPaymentTravellerId == draftId);
                }
                return Ok(new
                {
                    posConfig = posConfig,
                    currencies = currencies,
                    currenciesISO = currenciesISO,
                    defaultCurrency = defaultCurrency,
                    extraServices = extraServices,
                    paymentMethods = paymentMethods,
                    countries = countries,
                    companyList = companyList,
                    draftData = draftData
                });
            }
            return Ok();
        }

        [HttpGet]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetPOSInvoiceDetail")]
        public async Task<IHttpActionResult> GetPOSInvoiceDetail(int invoiceId)
        {
            //context.DeferredLoadingEnabled = false;
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Single(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                var currentInvoice = currentHotel.POSPaymentTravellersList.Single(inv => inv.POSPaymentTravellerId == invoiceId);
                if (currentInvoice != null)
                {
                    List<Staffs> ListUser = context.Staffs.Where(s => s.HotelId == user.HotelId).ToList();
                    string hotelOwnerId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().HotelOwnerId;
                    var userOwner = context.AspNetUsers.Where(u => u.Id == hotelOwnerId).FirstOrDefault();
                    ListUser.Add(
                        new Staffs()
                        {
                            Email = userOwner.Email,
                            UserId = hotelOwnerId
                        });

                    var createdInvoiceUser = currentInvoice.CreatedUserAspNetUsers;
                    var travellers = currentInvoice.Travellers;
                    var roomExtraServiceList = currentInvoice.RoomExtraServicesList.ToList();
                    foreach (var es in roomExtraServiceList)
                    {
                        var createdUser = es.CreatedUserAspNetUsers.Email;
                    }
                    var roomExtraServiceItemsList = currentInvoice.RoomExtraServiceItemsList.ToList();
                    foreach (var item in roomExtraServiceItemsList)
                    {
                        var extraServiceItems = item.ExtraServiceItems;
                    }
                    var ptps = currentInvoice.POSPaymentTravellerPaymentsList.ToList();
                    foreach (var ptp in ptps)
                    {
                        var payment = ptp.Payments;
                        var paymentMethods = ptp.Payments.PaymentMethods;
                        var money = payment.Money;
                        var currency = money.Currencies;
                        var createdUser = payment.CreatedUserAspNetUsers;
                    }
                    return Ok(new { currentInvoice, listUser = ListUser, posConfig = currentHotel.POSConfigsList.FirstOrDefault() });
                    //return Ok(currentInvoice);
                }
                else
                {
                    return Ok();
                }
            }
            return Ok();
        }

        [HttpGet]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetPOSConfig")]
        public async Task<IHttpActionResult> GetPOSConfig()
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                return Ok(currentHotel.POSConfigsList.FirstOrDefault());
            }
            return Ok();
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SavePOSConfig")]
        public async Task<IHttpActionResult> SavePOSConfig(POSConfigs model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                if (model.POSConfigId == 0)
                {
                    model.Hotels = currentHotel;
                    context.POSConfigs.InsertOnSubmit(model);
                }
                else
                {
                    currentHotel.POSConfigsList.FirstOrDefault().InvoiceType = model.InvoiceType;
                    currentHotel.POSConfigsList.FirstOrDefault().NumberOfDateToRemoveDrafBill = model.NumberOfDateToRemoveDrafBill;
                }
                context.SubmitChanges();
            }
            return Ok();
        }


        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SavePOSInvoice")]
        public async Task<IHttpActionResult> SavePOSInvoice(POSModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                if (Math.Round((decimal)model.Charges.Sum(s => s.Price * s.Quantity) - model.Payments.Sum(p => (decimal)p.Amount) - (decimal)model.DiscountAmount) == 0)
                {
                    model.ContactInformation.HotelId = currentHotel.HotelId;
                    model.ContactInformation.CreatedDate = DateTime.UtcNow;
                    model.ContactInformation.CreatedUserId = user.UserId;
                    model.ContactInformation.Birthday = model.ContactInformation.Birthday != null ? model.ContactInformation.Birthday.Value.AddMinutes(currentHotel.TimeZoneOffset) : model.ContactInformation.Birthday;
                    var posPaymentTravellres = new POSPaymentTravellers()
                    {
                        HotelId = currentHotel.HotelId,
                        POSPaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "POS"),
                        Travellers = model.ContactInformation,
                        CreatedDate = DateTime.UtcNow,
                        CreatedUserId = user.UserId,
                        DiscountFlat = (decimal)model.DiscountFlat,
                        DiscountPercentage = model.DiscountPercentage,
                        DiscountReason = model.DiscountReason,
                        DiscountAmount =(decimal) model.DiscountAmount,
                        IsDeleted = false
                    };
                    if (model.DiscountFlat != 0 || model.DiscountPercentage != 0)
                    {
                        posPaymentTravellres.DiscountCreatedDate = DateTime.UtcNow;
                    }
                    context.POSPaymentTravellers.InsertOnSubmit(posPaymentTravellres);

                    foreach (var payment in model.Payments)
                    {
                        payment.HotelId = user.HotelId;
                        payment.ReservationRoomId = null;
                        payment.PaymentTypeName = "NEW_PAYMENT";
                        payment.CreatedDate = payment.CreatedDate;
                        payment.CreatedUserId = user.UserId;
                        payment.PaymentNumber = null;
                        payment.CompanyId = payment.CompanyId;
                        payment.IsPOS = true;
                        context.Payments.InsertOnSubmit(payment);
                        var posPaymentTravellersPayments = new POSPaymentTravellerPayments()
                        {
                            POSPaymentTravellers = posPaymentTravellres,
                            Payments = payment,
                            HotelId = currentHotel.HotelId,
                            POSPaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "POSPAYMENTNUMBER")
                        };
                        context.POSPaymentTravellerPayments.InsertOnSubmit(posPaymentTravellersPayments);
                    }
                    foreach (var item in model.Charges)
                    {
                        if (item.Type == "EXTRA_SERVICE_ITEM")
                        {
                            var roomExtraServices = new RoomExtraServices()
                            {
                                RoomExtraServiceName = "POS",
                                RoomExtraServiceDescription = "POS_WITH_ITEMS",
                                HotelId = currentHotel.HotelId,
                                ReservationRoomId = null,
                                Quantity = 1,
                                Amount = item.Price * item.Quantity,
                                CreatedUserId = user.UserId,
                                CreatedDate = DateTime.UtcNow,
                                RoomExtraServiceNumber = null,
                                POSPaymentTravellers = posPaymentTravellres
                            };
                            context.RoomExtraServices.InsertOnSubmit(roomExtraServices);
                            var roomExtraServiceItems = new RoomExtraServiceItems()
                            {
                                HotelId = currentHotel.HotelId,
                                RoomExtraServices = roomExtraServices,
                                ReservationRoomId = null,
                                //Price = item.Price * item.Quantity,
                                Price = item.Price,
                                Quantity = item.Quantity,
                                ExtraServiceItemId = item.Id,
                                POSPaymentTravellers = posPaymentTravellres
                            };
                            context.RoomExtraServiceItems.InsertOnSubmit(roomExtraServiceItems);
                        }
                        else
                        {
                            var roomExtraServices = new RoomExtraServices()
                            {
                                RoomExtraServiceName = "POS_EXTRA_SERVICES",
                                RoomExtraServiceDescription = item.Name,
                                HotelId = currentHotel.HotelId,
                                ReservationRoomId = null,
                                Quantity = item.Quantity,
                                Amount = item.Price ,
                                CreatedUserId = user.UserId,
                                CreatedDate = DateTime.UtcNow,
                                RoomExtraServiceNumber = null,
                                POSPaymentTravellers = posPaymentTravellres
                            };
                            context.RoomExtraServices.InsertOnSubmit(roomExtraServices);
                        }
                    }
                    context.SubmitChanges();

                    Notification.processNotificationPOSAddNewPayment(model, (int)posPaymentTravellres.POSPaymentNumber, user);
                    Common.Elastic.IndexLastAudit(context);
                    return Ok(posPaymentTravellres.POSPaymentTravellerId);
                }
                else
                {
                    return BadRequest("SOME_ERROR_HAS_OCCURRED_DURING_SAVE_INVOICE_PROCESSING");
                }
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessDeletePOSInvoice")]
        public async Task<IHttpActionResult> ProcessDeletePOSInvoice(DeleteInvoiceModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                if (model.isInvoice)
                {
                    var currentInvoice = currentHotel.POSPaymentTravellersList.FirstOrDefault(inv => inv.POSPaymentTravellerId == model.Id);
                    if (currentInvoice != null)
                    {
                        currentInvoice.IsDeleted = true;
                        currentInvoice.DeletedDate = DateTime.UtcNow;
                        currentInvoice.DeletedUserId = user.UserId;
                        currentInvoice.DeletedReason = model.DeleteReason;
                        var posPaymentList = currentInvoice.POSPaymentTravellerPaymentsList;
                        decimal totalAmountDelete = 0;
                        foreach(var posPayment in posPaymentList)
                        {
                            var payment = posPayment.Payments;
                            if (payment.PaymentTypeName != "DELETED" && payment.RefPaymentId == null && payment.IsPOS == true)
                            {
                                Payments deletedPayment = new Payments();

                                //deletedPayment = payment;
                                deletedPayment.HotelId = user.HotelId;
                                deletedPayment.Amount = -payment.Amount;
                                deletedPayment.CreatedDate = DateTime.UtcNow;
                                deletedPayment.PaymentTypeName = "DELETED";
                                deletedPayment.CreatedUserId = user.UserId;
                                deletedPayment.IsPOS = true;
                                deletedPayment.RefPayments = payment;
                                deletedPayment.PaymentMethodId = payment.PaymentMethodId;
                                deletedPayment.MoneyId = payment.MoneyId;
                                deletedPayment.PaymentDescription = model.DeleteReason;
                                deletedPayment.CompanyId = payment.CompanyId;
                                context.Payments.InsertOnSubmit(deletedPayment);
                                payment.RefPayments = deletedPayment;

                                totalAmountDelete += totalAmountDelete + (decimal)payment.Amount;
                            }
                        }

                        var roomES = currentInvoice.RoomExtraServicesList;
                        foreach(var es in roomES)
                        {
                            es.DeletedDate = DateTime.UtcNow;
                            es.DeletedBy = user.UserId;
                            es.IsDeleted = true;
                            es.DeletedReason = model.DeleteReason;
                        }

                        var roomESItems = currentInvoice.RoomExtraServiceItemsList;
                        foreach (var item in roomESItems)
                        {
                            item.DeletedDate = DateTime.UtcNow;
                            item.DeletedBy = user.UserId;
                            item.IsDeleted = true;
                            item.DeletedReason = model.DeleteReason;
                        }

                        Notification.processNotificationPOSDeleteInvoice(model, totalAmountDelete, (int)currentInvoice.POSPaymentNumber, user);
                    }
                }
                else
                {
                    context.ExecuteCommand("Delete DrafPOSPaymentTraveller where HotelId={0} and DrafPOSPaymentTravellerId={1}", user.HotelId, model.Id);
                }

                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SavePOSInvoiceToDraft")]
        public async Task<IHttpActionResult> SavePOSInvoiceToDraft(POSDraftModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null && CheckIfPOSModuleUsed(currentHotel))
            {
                if (model.DrafPOSPaymentTravellerId == null)
                {
                    var draftPOS = new DrafPOSPaymentTraveller
                    {
                        HotelId = currentHotel.HotelId,
                        CreatedDate = DateTime.UtcNow,
                        CreatedUserId = user.UserId,
                        Title = model.Title,
                        DrafPOSData = Newtonsoft.Json.JsonConvert.SerializeObject(model)
                    };
                    context.DrafPOSPaymentTraveller.InsertOnSubmit(draftPOS);
                    context.SubmitChanges();
                }
                else
                {
                    var currentDraft = currentHotel.DrafPOSPaymentTravellerList.FirstOrDefault(draft => draft.DrafPOSPaymentTravellerId == model.DrafPOSPaymentTravellerId);
                    if (currentDraft != null)
                    {
                        currentDraft.DrafPOSData = Newtonsoft.Json.JsonConvert.SerializeObject(model);
                        currentDraft.CreatedDate = DateTime.UtcNow;
                        currentDraft.CreatedUserId = user.UserId;
                        currentDraft.Title = model.Title;
                    }
                    context.SubmitChanges();
                }
                
            }
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchInvoiceProcess")]
        public async Task<IHttpActionResult> SearchInvoiceProcess(SearchInvoiceModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);

            if (model.InvoiceCreatedDateFrom == null)
            {
                model.InvoiceCreatedDateFrom = ((DateTime)SqlDateTime.MinValue).Date;
            }
            if (model.InvoiceCreatedDateTo == null)
            {
                model.InvoiceCreatedDateTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            if (model.InvoiceCreatedDateFrom != null)
            {
                DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.InvoiceCreatedDateFrom).Year, ((DateTime)model.InvoiceCreatedDateFrom).Month, ((DateTime)model.InvoiceCreatedDateFrom).Day, ((DateTime)model.InvoiceCreatedDateFrom).Hour, ((DateTime)model.InvoiceCreatedDateFrom).Minute, ((DateTime)model.InvoiceCreatedDateFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                model.InvoiceCreatedDateFrom = fromTemp.Date;
            }
            if (model.InvoiceCreatedDateTo != null)
            {
                DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.InvoiceCreatedDateTo).Year, ((DateTime)model.InvoiceCreatedDateTo).Month, ((DateTime)model.InvoiceCreatedDateTo).Day, ((DateTime)model.InvoiceCreatedDateTo).Hour, ((DateTime)model.InvoiceCreatedDateTo).Minute, ((DateTime)model.InvoiceCreatedDateTo).Second, offSet).ToOffset(TimeSpan.Zero);
                model.InvoiceCreatedDateTo = toTemp.Date;
            }
            if (model.InvoiceCreatedDateFrom == model.InvoiceCreatedDateTo) model.InvoiceCreatedDateTo = model.InvoiceCreatedDateTo.Value.Date.AddDays(1);
            List<Staffs> ListUser = context.Staffs.Where(s => s.HotelId == user.HotelId).ToList();
            string hotelOwnerId = context.Hotels.Where(h => h.HotelId == user.HotelId).FirstOrDefault().HotelOwnerId;
            var userOwner = context.AspNetUsers.Where(u => u.Id == hotelOwnerId).FirstOrDefault();
            ListUser.Add(
                new Staffs()
                {
                    Email = userOwner.Email,
                    UserId = hotelOwnerId
                });

            if (model.InvoiceType == 1)
            {
               
                var q = context.POSPaymentTravellers.Where(pos => pos.HotelId == user.HotelId && pos.IsDeleted == false);
                if (model.InvoiceNumber != null)
                {
                    q = q.Where(number => number.POSPaymentNumber == model.InvoiceNumber);
                }
                
                
               // model.InvoiceCreatedDateFrom = model.InvoiceCreatedDateFrom ?? DateTime.MinValue;
               // model.InvoiceCreatedDateTo = model.InvoiceCreatedDateTo ?? DateTime.MaxValue;
                q = q.Where(inv => inv.CreatedDate <= model.InvoiceCreatedDateTo && inv.CreatedDate >= model.InvoiceCreatedDateFrom);
                if (model.InvoiceCustomerName != null)
                {
                    q = q.Where(inv => SqlMethods.Like(inv.Travellers.Fullname, "%" + model.InvoiceCustomerName + "%"));
                }
                var result = q.OrderByDescending(o => o.CreatedDate).Select(pos => new
                {
                    pos.POSPaymentTravellerId,
                    pos.POSPaymentNumber,
                    pos.CreatedDate,
                    pos.CreatedUserAspNetUsers.Email,
                    pos.CreatedUserId,
                    pos.Travellers.Fullname
                }).ToList();
                return Ok( new { result, listUser=ListUser });
            }
            else
            {
                var q = context.DrafPOSPaymentTraveller.Where(draft => draft.HotelId == user.HotelId);
               // model.InvoiceCreatedDateFrom = model.InvoiceCreatedDateFrom ?? DateTime.MinValue;
               // model.InvoiceCreatedDateTo = model.InvoiceCreatedDateTo ?? DateTime.MaxValue;
                q = q.Where(inv => inv.CreatedDate <= model.InvoiceCreatedDateTo && inv.CreatedDate >= model.InvoiceCreatedDateFrom);
                if (model.InvoiceTitle != null)
                {
                    q = q.Where(inv => SqlMethods.Like(inv.Title, "%" + model.InvoiceTitle + "%"));
                }
                var result = q.OrderByDescending(o => o.CreatedDate).Select(pos => new
                {
                    pos.DrafPOSPaymentTravellerId,
                    pos.CreatedDate,
                    pos.CreatedUserAspNetUsers.Email,
                    pos.CreatedUserId,
                    pos.Title,
                }).ToList();
                return Ok(new { result, listUser = ListUser });
            }
        }

        public class ChargeItem
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Quantity { get; set; }
            public decimal Price { get; set; }
            public string Type { get; set; }
        }

        public class POSModel
        {
            public Travellers ContactInformation { get; set; }
            public List<ChargeItem> Charges { get; set; }
            public List<Payments> Payments { get; set; }
            public double DiscountFlat { get; set; }
            public float DiscountPercentage { get; set; }
            public string DiscountReason { get; set; }
            public double DiscountAmount { get; set; }

            public Hashtable languageKeys { get; set; }
        }

        public class POSDraftModel
        {
            public int? DrafPOSPaymentTravellerId { get; set; }
            public string Title { get; set; }
            public Travellers ContactInformation { get; set; }
            public List<ChargeItem> Charges { get; set; }
            public List<Payments> Payments { get; set; }
            public double DiscountFlat { get; set; }
            public float DiscountPercentage { get; set; }
            public string DiscountReason { get; set; }
            public double DiscountAmount { get; set; }
        }

        public class SearchInvoiceModel
        {
            public int? InvoiceNumber { get; set; }
            public int InvoiceType { get; set; }
            public string InvoiceCustomerName { get; set; }
            public DateTime? InvoiceCreatedDateFrom { get; set; }
            public DateTime? InvoiceCreatedDateTo { get; set; }
            public string InvoiceTitle { get; set; }
        }

        public class DeleteInvoiceModel
        {
            public int Id { get; set; }
            public bool isInvoice { get; set; }
            public string DeleteReason { get; set; }
            public Hashtable languageKeys { get; set; }
        }
    }
}